package com.ly.common.util;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;
import java.util.*;

public class IOUtils {

    /**
     * 关闭流
     *
     * @param cs
     */
    public static void close(AutoCloseable... cs) {
        for (AutoCloseable c : cs) {
            if (c != null)
                try {
                    c.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
        }
    }

    /**
     * 字节流复制
     *
     * @param in
     * @param out
     * @throws IOException
     */
    public static void transfer(InputStream in, OutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        int count;
        while ((count = in.read(buffer)) > -1) {
            out.write(buffer, 0, count);
        }
    }

    /**
     * 字符流复制
     *
     * @param in
     * @param out
     * @throws IOException
     */
    public static void transfer(Reader in, Writer out) throws IOException {
        char[] buffer = new char[1024];
        int count;
        while ((count = in.read(buffer)) > -1) {
            out.write(buffer, 0, count);
        }
    }

    /**
     * 判断是否是图片文件
     *
     * @param filepath
     * @return
     */
    public static boolean isImageFile(String filepath) {
        try {
            Image image = ImageIO.read(new File(filepath));
            return image != null;
        } catch (IOException ex) {
            ex.printStackTrace();
            return false;
        }
    }

    /**
     * 图片缩放
     *
     * @param src       源文件
     * @param maxWidth
     * @param maxHeight
     * @param suffix    新文件插入的新后缀名  例如: suffix="_m" => a.jpg => a_m.jpg
     * @return
     */
    public static String scale(String src, int maxWidth, int maxHeight, String suffix) {
        String dest = src.replaceAll("(.+)(\\.\\w+)", "$1" + suffix + "$2");
        scale(src, dest, maxWidth, maxHeight);
        return dest;
    }

    /**
     * 图片缩放
     *
     * @param src       源文件
     * @param dest      目标文件
     * @param maxWidth
     * @param maxHeight
     */
    public static void scale(String src, String dest, int maxWidth, int maxHeight) {
        try {
            BufferedImage isrc = ImageIO.read(new File(src));
            int sw = isrc.getWidth();
            int sh = isrc.getHeight();
            double wr = (double) maxWidth / sw;
            double hr = (double) maxHeight / sh;
            double r = Math.max(wr, hr);
            int dw = (int) (sw * r);
            int dh = (int) (sh * r);
            Image image = isrc.getScaledInstance(dw, dh, Image.SCALE_DEFAULT);
            BufferedImage idest = new BufferedImage(dw, dh, BufferedImage.TYPE_INT_RGB);
            Graphics g = idest.getGraphics();
            g.drawImage(image, 0, 0, null);
            g.dispose();
            String suffix = src.replaceAll(".+\\.(\\w+)", "$1");
            ImageIO.write(idest, suffix.toLowerCase(), new File(dest));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 读入文件, 内容保存为字符串
     *
     * @param f
     * @return
     * @throws IOException
     */
    public static String fileToString(File f) throws IOException {
        FileReader fr = null;
        StringWriter sw = null;
        try {
            fr = new FileReader(f);
            sw = new StringWriter();
            transfer(fr, sw);
            return sw.toString();
        } finally {
            close(fr, sw);
        }
    }

    public static Iterable<String> eachLine(String filepath) {
        try {
            return eachLine(new FileReader(filepath));
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public static Iterable<String> eachLine(InputStream in) {
        return eachLine(new InputStreamReader(in));
    }

    public static Iterable<String> eachLine(Reader reader) {
        BufferedReader br = new BufferedReader(reader);
        return new Iterable<String>() {
            @Override
            public Iterator<String> iterator() {
                return new Iterator<String>() {
                    String line;

                    @Override
                    public boolean hasNext() {
                        try {
                            return (line = br.readLine()) != null;
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }

                    @Override
                    public String next() {
                        return line;
                    }
                };
            }
        };
    }

    /**
     * 文件树
     * @param dir
     * @param includes
     * @return
     */
    public static List<Object> fileTree(String dir, String... includes) {
        File file = new File(dir);
        return fileTree(file, file, new ArrayList<>(), includes);
    }

    private static List<Object> fileTree(File dir, String... includes) {
        if (dir.isDirectory()) {
            return fileTree(dir, dir, new ArrayList<>(), includes);
        } else {
            return null;
        }
    }

    private static List<Object> fileTree(File baseDir, File dir, List<Object> list, String... includes) {
        File[] files = dir.listFiles((f) -> {
            boolean result = true;
            if (includes != null && includes.length > 0 && f.isFile()) {
                result = false;
                for (String include : includes) {
                    include = include.replaceAll("\\.", "\\\\.").replaceAll("\\*", "\\.*");
                    if (f.getName().matches(include)) {
                        result = true;
                        break;
                    }
                }
            }
            if (result) {
                Map<String, Object> map = new HashMap<>();
                map.put("name", f.getName());
                map.put("path", f.getAbsolutePath().replace(baseDir.getAbsolutePath(), "").replaceAll("\\\\", "/"));
                if (f.isDirectory()) {
                    List<Object> l = fileTree(baseDir, f, new ArrayList<>(), includes);
                    if (l.isEmpty() == false) {
                        map.put("children", l);
                    } else {
                        return false;
                    }
                }
                list.add(map);
            }
            return false;
        });
        return list;
    }

    public static interface CallerWithReturn {
        Object handle(Closeable... params) throws Exception;
    }

    public static interface CallerNotReturn {
        void handle(Closeable... params) throws Exception;
    }

    public static Object call(CallerWithReturn caller, Closeable... closeables) {
        try {
            return caller.handle(closeables);
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException("call error", e);
        } finally {
            for (Closeable p : closeables) {
                try {
                    p.close();
                } catch (Exception e) {
                    throw new RuntimeException("close error", e);
                }
            }
        }
    }

    public static void exec(CallerNotReturn caller, Closeable... closeables) {
        try {
            caller.handle(closeables);
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException("call error", e);
        } finally {
            for (Closeable p : closeables) {
                try {
                    p.close();
                } catch (Exception e) {
                    throw new RuntimeException("close error", e);
                }
            }
        }
    }

}
